//package modified_snake_game;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

@SuppressWarnings("serial")
public class Board extends JPanel implements ActionListener {

	private int WIDTH = 300;				// board width
	private int HEIGHT = 300;				// board height
	private int DELAY = 140;				// controls the speed of the snake
	private final int DOT_SIZE = 10;		// spacing between the snake
	private final int ALL_DOTS = 900;
	private final int RAND_POS = 29;
	private int bgcolor = 0;
	private int score = 0;
	private int level = 0;

	private int x[] = new int[ALL_DOTS];
	private int y[] = new int[ALL_DOTS];

	private int dots;
	private int apple_x;
	private int apple_y;

	private boolean left = false;
	private boolean right = true;
	private boolean up = false;
	private boolean down = false;
	private boolean inGame = true;

	private Timer timer;
	private Image ball;
	private Image apple;
	private Image head;

	private Image wall;    //image of a wall
	private int wall_x;    //variable wall_x used to keep track of random position
	private int wall_y;    //variable wall_y used to keep track of random position

	private Image portal;    //image of a portal
	private int portal_x;    //variable portal_x used to keep track of random position
	private int portal_y;    //variable portal_y used to keep track of random position
	
	private int[] portal_exit_x = new int [ALL_DOTS];
	private int[] portal_exit_y = new int [ALL_DOTS];
	
	/**
	 * Creates a new board, and places all the pieces into there places.
	 * - the snake, moving wall, and apple
	 */
    public Board(int width, int height, int speed, int bgcolor) 
    {
    	System.out.println("b.height: " + HEIGHT);
    	this.HEIGHT = height;
    	System.out.println("a.height: " + HEIGHT);
    	System.out.println("b.width: " + WIDTH);
    	this.WIDTH = width;
    	System.out.println("a.width: " + WIDTH);
    	System.out.println("b.speed: " + DELAY);
    	this.DELAY = speed;
    	System.out.println("b.speed: " + DELAY);

		addKeyListener(new TAdapter());

		/**
		 * By using different colors, we need to change the boarders of the pictures.
		 * For now, I'm leaving it with this color, just to see what we are working with
		 * if you want to comment the code out and use the above, "original code" that's
		 * totally fine with me.
		 * 
		 * My goal is that, I'm hoping to have different pictures in the backgrounds such as:
		 * - forests, deserts, water, etc.
		 * 
		 * ---Jordan, below is a list of already inputed valid colors, there is an option to 
		 *    there is an option to create your own colors, do you want to give the users that
		 *    option?
		 */
		switch(bgcolor)
		{
		case 1:
			setBackground(Color.cyan);
			break;
		case 2:
			setBackground(Color.blue);
			break;
		case 3:
			setBackground(Color.darkGray);
			break;
		case 4:
			setBackground(Color.gray);
			break;
		case 5:
			setBackground(Color.green);
			break;
		case 6:
			setBackground(Color.lightGray);
			break;
		case 7:
			setBackground(Color.magenta);
			break;
		case 8:
			setBackground(Color.orange);
			break;
		case 9:
			setBackground(Color.pink);
			break;
		case 10:
			setBackground(Color.red);
			break;
		case 11:
			setBackground(Color.white);
			break;
		case 12:
			setBackground(Color.yellow);
			break;
		case 13:
			setBackground(Color.black);
			break;
		default:
			setBackground(Color.black);
			break;
		}

		ImageIcon iid = new ImageIcon(this.getClass().getResource("dot.png"));
		ball = iid.getImage();

		ImageIcon iia = new ImageIcon(this.getClass().getResource("apple.png"));
		apple = iia.getImage();

		ImageIcon iih = new ImageIcon(this.getClass().getResource("head.png"));
		head = iih.getImage();

		/**
		 * This code places the moving wall on the board
		 */
		ImageIcon iiw = new ImageIcon(this.getClass().getResource("wall.png"));
		wall = iiw.getImage();
		
		/**
		 * This code places a portal on the board
		 */
		ImageIcon iip = new ImageIcon(this.getClass().getResource("portal.png"));
		portal = iip.getImage();

		setFocusable(true);
		initGame();
	}


	/**
	 * Initiates the game with:
	 * - snake = length3
	 * - where the snake starts
	 * - places a apple in a random position on the map
	 * - places a moving wall in a random position on the map
	 */
	public void initGame() {
		dots = 3;

		//the map is currently a 300x300 map
		for (int z = 0; z < dots; z++) {
			x[z] = 50 - z*10; //width or horizontal axis
			y[z] = 50;        //height or vertical axis
		}

		locateApple();        //places an apple, randomly on the map
		locateWall();         //places a wall, randomly on the map
		locatePortal();       //places a portal, randomly on the map


		timer = new Timer(DELAY, this);
		timer.start();
	}

	
	/**
	 * Paints the different images onto the board:
	 * - apples
	 * - moving walls
	 * - game over screen
	 */
	public void paint(Graphics g) {
		super.paint(g);

		if (inGame) {
			g.drawImage(apple, apple_x, apple_y, this);    //creates a new apple image
			g.drawImage(wall, wall_x, wall_y, this);       //creates a new wall image
			g.drawImage(portal, portal_x, portal_y, this); //creates a new portal image


			//chooses a random spot on the map to place the images
			for (int z = 0; z < dots; z++) {
				if (z == 0)
					g.drawImage(head, x[z], y[z], this);
				else g.drawImage(ball, x[z], y[z], this);
			}

			Toolkit.getDefaultToolkit().sync();
			g.dispose();

		} else {
			gameOver(g);
		}
	}


	/**
	 * Creates the game over screen, once the game is over.
	 */
	public void gameOver(Graphics g) {
		String msg = "Game Over";
		Font small = new Font("Helvetica", Font.BOLD, 14);
		FontMetrics metr = this.getFontMetrics(small);

		g.setColor(Color.white);
		g.setFont(small);
		g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2);
		
		Scores.addNewScore(score, level);
	}


	/**
	 * If apple is eaten:
	 * - increase dots (size of snake by 1)
	 * - place another apple in a random spot
	 * - place another moving wall in a random spot
	 */
	public void checkApple() {
		if ((x[0] == apple_x) && (y[0] == apple_y)) {
			dots++;        //increments the size of the snake
			locateApple(); //places a new apple
			locateWall();  //places a new wall
			locatePortal();//places a new portal
		}
	}


	/**
	 * Takes input in order to move the snake.
	 */
	public void move() {
		for (int z = dots; z > 0; z--) {
			x[z] = x[(z - 1)];
			y[z] = y[(z - 1)];
		}

		if (left) {
			x[0] -= DOT_SIZE;
		}

		if (right) {
			x[0] += DOT_SIZE;
		}

		if (up) {
			y[0] -= DOT_SIZE;
		}

		if (down) {
			y[0] += DOT_SIZE;
		}
	}


	/**
	 * Checks to see if the snake has hit obstacle or wall, and if so
	 * the game is over.
	 */
	public void checkCollision() {
		
		//checks if snake hits itself
		for (int z = dots; z > 0; z--) {
			if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {
				inGame = false;
			}
		}

		//next 4 if's determine boarder
		if (y[0] > HEIGHT) {
			inGame = false;
		}

		if (y[0] < 0) {
			inGame = false;
		}

		if (x[0] > WIDTH) {
			inGame = false;
		}

		if (x[0] < 0) {
			inGame = false;
		}
	}

	
	/**
	 * Method that puts an apple in a random position on the map
	 */
	public void locateApple() {
		int r = (int) (Math.random() * RAND_POS);
		apple_x = ((r * DOT_SIZE));
		r = (int) (Math.random() * RAND_POS);
		apple_y = ((r * DOT_SIZE));
	}


	/**
	 * Method that puts a moving wall in a random position on the map
	 */
	public void locateWall() {
		int r = (int) (Math.random() * RAND_POS);
		wall_x = ((r * DOT_SIZE));
		r = (int) (Math.random() * RAND_POS);
		wall_y = ((r * DOT_SIZE));
	}

	/**
	 * If moving wall is hit, the game is over.
	 */
	public void checkWall() {
		if ((x[0] == wall_x) && (y[0] == wall_y)) {
			inGame = false;
		}
	}

	/**
	 * Method that puts a portal in a random position on the map
	 */
	public void locatePortal() {
		int r = (int) (Math.random() * RAND_POS);
		portal_x = ((r * DOT_SIZE));
		r = (int) (Math.random() * RAND_POS);
		portal_y = ((r * DOT_SIZE));
		portal_exit_x[0] = portal_x; //where the portal will exit
		portal_exit_y[0] = portal_y; //where the portal will exit
		System.out.println("Axis x: " + portal_exit_x[0]);
		System.out.println("Axis y: " + portal_exit_y[0]);
		System.out.println();
	}

	/**
	 * When portal is entered, send snake somewhere else
	 * Currently the snake is set to teleport to the original spot it starts in
	 * It also calls a new apple, wall and portal locations
	 */
	public void checkPortal() {
		if ((x[0] == portal_x) && (y[0] == portal_y)) {
			//inGame = false;
			//initGame();
			for (int z = 0; z < dots; z++) {
				x[z] = 50 - z*10; //width or horizontal axis
				y[z] = 50;        //height or vertical axis
			}

			locateApple();        //places an apple, randomly on the map
			locateWall();         //places a wall, randomly on the map
			locatePortal();       //places a portal, randomly on the map

		}
	}
	
	/**
	 * Checks the actions performed, makes sure that game is still going.
	 */
	public void actionPerformed(ActionEvent e) {
		if (inGame) {
			checkApple();
			checkWall();
			checkPortal();
			checkCollision();
			move();

			/**
			 * By adding move() == makes the game speed up exponentially.
			 * This could be used as a setting "speed up snake"
			 */
			//move();
		}
		repaint();
	}


	/**
	 * Getter used to check if snake game should still be running
	 * @return
	 */
	public boolean isInGame() {
		return inGame;
	}


	/**
	 * Setter used to change if snake game should still be running
	 * @param inGame
	 */
	public void setInGame(boolean inGame) {
		this.inGame = inGame;
	}


	/**
	 * This Method starts up the whole snake GUI.
	 * @author Jordan B. & Reed P.
	 */
	private class TAdapter extends KeyAdapter {
		public void keyPressed(KeyEvent e) {
			int key = e.getKeyCode();

			if ((key == KeyEvent.VK_LEFT) && (!right)) {
				left = true;
				up = false;
				down = false;
			}

			if ((key == KeyEvent.VK_RIGHT) && (!left)) {
				right = true;
				up = false;
				down = false;
			}

			if ((key == KeyEvent.VK_UP) && (!down)) {
				up = true;
				right = false;
				left = false;
			}

			if ((key == KeyEvent.VK_DOWN) && (!up)) {
				down = true;
				right = false;
				left = false;
			}
		}
	}
}